#include <at89x51.h>
/* wersja z wylaczona na stale dioda i klawiatura obslugiwana bezposrednio przez procesor - brak dodatkowego ukladu 74HC21 
  nie ma wtedy przerwania zewnetrznego 
   T0 ma najwyzszy priorytet - zglaszane jest zawsze co 50ms i wtedy dokonywane jest badanie wszystkiego i podejmowane akcje*/

#define QUARTZ_FAKTOR 1229	/*OKOLO... =osc.in kHz /12 */
#define IDLE_MODE PCON|=1; /*idle mode*/
#define POWER_DOWN_MODE PCON|=2; /*power down mode*/
/*nowe: dioda na P0.0,  zaplon na P0.1, pompka na P0.2, syrena ma P0.3 */
#define ZAPLON	P0_1
#define POMPKA	P0_2
#define DIODA	P0_0
#define SYRENA	P0_3
#define BUZZER	P0_4
/*#define USTAW_WYNIK P0=wynik;*/
#define ON	0
#define OFF	1
#define ZAPLON_ON	ZAPLON=ON;
#define ZAPLON_OFF	ZAPLON=OFF;
#define POMPKA_ON	POMPKA=ON;
#define POMPKA_OFF	POMPKA=OFF;
#define SYRENA_ON	SYRENA=ON;
#define SYRENA_OFF	SYRENA=OFF;
#define BUZZER_ON	BUZZER=ON;
#define BUZZER_OFF	BUZZER=OFF;
/* ponizsze dwa zrobine na potrzeby migotania dioda czuwania */
#define DIODA_ON 	DIODA=ON;
#define DIODA_OFF 	DIODA=OFF;
/* stany wyjscia komputerka */
#define DISARMED	rozbrojenie();
#define ALARM		alarmik();
#define CZUWANIE	czuwanko();
/* funkcje pomocnicze */
#define STOP_TIME_OUT	time_out_enabled=0;/*TR1=0;*/
#define STOP_POWER_DOWN_TIME_OUT	ET1=0; TR1=0;
#define INVALID_KEYBOARD_SNAP_SHOT	0xFF

/* predefiniowane klawisze */
#define CHECK_BTN	10
#define CHECK_BTN2	11
#define L1	2
#define L2	6
#define L3	9
#define L4	6
#define L5	7
#define L6	4
#define Z1	3
#define Z2	5
#define Z3	8
#define Z4	4
#define Z5	1

#define bit __sbit

typedef enum {start=0,ST1,ST2,ST3,ST4,ST5,ST6,ST7,ST8,zlodziej,zl1,zl2,zl3,zl4} stany;
stany stan;
/* unsigned char wynik;*/
unsigned char keyboardSnapShot; /*pomocny do scanowania klawiatury 
								- jedna wartosc zakazana dla okreslenia 
								ze nie bylo puszczenia klawisza*/
unsigned char wiersz;
unsigned char kolumna;
unsigned char klawisz;
unsigned char diode_times;
unsigned char buzzer_times;
/* znaczniki zdarzen*/
bit klawiatura;
/* okreslenie time-outow */
bit time_out;
int time_out_repetitions;
bit time_out_enabled;	/* okresla ze time out zostal uruchomiony - takich timerow mozna zrobic wiecej w razie potrzeby*/
/* time out 1*/
bit time_out1;
int time_out1_repetitions;
bit time_out1_enabled; /* time out do "blinkowania" dioda */
////////////////////////
// bit okreslajacy czy w danym stanie ma byc uzyty BUZZER na 10 sekund przed koncem time-outu
bit buz;
bit buzzer_time_out;
bit buzzer_time_out_enabled;
unsigned char buzzer_time_out_repetitions;
/////////////////
// licznik odliczajacy do POWER_DOWN'a
unsigned char power_down;
/* badanie klawiatury co 50 ms - okreslanie czy za poprzednim razem byl wcisniety na podstawie keyboardSnapShot */

void startuj_time_out_power_down()
{
	TR1=0;	
	EA=0;
	TH1=0;
	TL1=0;
	power_down=0xff;
	ET1=1;
	EA=1;
	TR1=1;
}

void rozbrojenie()
{
	SYRENA_OFF POMPKA_ON ZAPLON_ON
}

void czuwanko()
{
	POMPKA_OFF ZAPLON_OFF SYRENA_OFF 
}

void alarmik()
{
	POMPKA_OFF ZAPLON_OFF SYRENA_ON DIODA_ON BUZZER_OFF /*wlaczona syrena....*/
}

void CNZ()
{
	/*przelacz sie do idle (chyba ze mozna do PowerDown - jesli moze wyjsc przez INTO) */
	/*najpierw ustawiamy przerwania*/
	/*EX0=1;*/
	EA=1;
	/*kasujemy bit zdarzen klawiatury - time_out i time_out1 kasowany powinien byc w miejscu gdzie jest on wykorzystany aby nie przegapic time-out'u na zlodzieja*/
	klawiatura=0;
	/* teraz przelaczamy sie na idle az pokaze sie jakies zdarzenie*/
	while (time_out==0 && klawiatura==0 && time_out1==0 && buzzer_time_out==0)
		IDLE_MODE
}

void inicjalizacja()
{
	if (stan!=start)
	{
		stan=zlodziej;
		ALARM
	}
	/* ustawianie przerwan, timerow i zmiennych */
	/*INTO wywolywany zmiana
	IT0=1;*/
	IP=0x08;	/* T1 ma wyzszy priorytet */
	IE=0x8A;	/*zezwolenie na przerwania od T0 i T1*/
	keyboardSnapShot=0x2B;
	klawiatura=0;
	time_out=0;
	time_out1=0;
	buzzer_time_out=0;
	buz=0;
	/*timer1 i timer0 w trybie 16-bitowym*/
	TMOD=0x11;	
	TH0=0x0F;	/*na 50 ms bo mozna maksymalnie na 53 z kawalkiem...*/
	TL0=0xEE;
	ET0=1;
	TR0=1;
}

void startuj_xtime_out(unsigned int milisecx100)	/*uzywany przy klawiaturze i zlodzieju*/
{
	TR0=0;	/*zatrzymujemy timer 0 */
	EA=0; /*blokujemy przerwania*/
	
	time_out=0;
	time_out_repetitions=milisecx100<<1;	/*ile setek milisekund - max. mozna 6553.5 sekundy*/
	time_out_enabled=1;
	EA=1;	/*odblokowujemy przerwania*/
	TR0=1; /*puszczamy timer 0*/
}

void startuj_xtime_out1(unsigned int milisecx100)	/*uzywany do migotania dioda*/
{
	TR0=0;	/*zatrzymujemy timer 0 */
	EA=0; /*blokujemy przerwania*/
	time_out1=0;
	time_out1_repetitions=milisecx100<<1;	/*ile setek milisekund - max. mozna 6553.5 sekundy*/
	time_out1_enabled=1;
	EA=1;	/*odblokowujemy przerwania*/
	TR0=1; /*puszczamy timer 0*/
}
void startuj_buzzer_time_out(unsigned char milisecx100)	/*uzywany do migotania buzzerem*/
{
	TR0=0;	/*zatrzymujemy timer 0 */
	EA=0; /*blokujemy przerwania*/
	buzzer_time_out=0;
	buzzer_time_out_repetitions=milisecx100<<1;	/*ile setek milisekund - max. mozna 6553.5 sekundy*/
	buzzer_time_out_enabled=1;
	EA=1;	/*odblokowujemy przerwania*/
	TR0=1; /*puszczamy timer 0*/
}


void blink_diode(unsigned char times)
{
	diode_times=times<<1; /* ile razy ma byc zapalona */
	DIODA_ON
	diode_times--;
	startuj_xtime_out1(2);
}

void blink_buzzer(unsigned char times)
{
	if (buz)
	{
		buzzer_times=times<<1;
		BUZZER_ON
		buzzer_times--;
		startuj_buzzer_time_out(5);
	}
}

void process_zdarzenie()
{
	/***********************************/
	/*		   blinkowanie dioda	   */
	if (time_out1)
	{
		time_out1=0;
		if (diode_times)
		{
			diode_times--;
			//DIODA=~DIODA;
			DIODA= !DIODA;
			startuj_xtime_out1(2);
		}
	}
	/***********************************/
	/* sygnalizacja dzwiekowa		   */
	if (buzzer_time_out)
	{
		buzzer_time_out=0;
		if (buzzer_times)
		{
			buzzer_times--;
			//BUZZER=~BUZZER;
			BUZZER= !BUZZER;
			if (buz)
				startuj_buzzer_time_out(5);
			else
				BUZZER_OFF
		}
	}
	/***********************************/
	/* obrobka time-out'u i klawiatury */
	switch(stan)
	{			/* w zaleznosci od stanu ustawiany jest tutaj wynik */
	case start:
		if (klawiatura)
		{
			if (klawisz==L1)
			{
				stan=ST1;
				CZUWANIE
				startuj_xtime_out(20);
			}
			else
			{
				if (klawisz==CHECK_BTN || klawisz==CHECK_BTN2)
					blink_diode(2);
			}
		}
		if (time_out)
		{
			time_out=0;
			STOP_TIME_OUT
			stan=start;
			CZUWANIE
		}
		break;
	case ST1:
		if (klawiatura)
		{
			if (klawisz==L2)
			{
				stan=ST2;
				CZUWANIE
				startuj_xtime_out(20);
			}
			else
			{
				stan=start;
				STOP_TIME_OUT
				CZUWANIE
			}
		}
		if (time_out)
		{
			time_out=0;
			STOP_TIME_OUT
			stan=start;
			CZUWANIE
		}
		break;
	case ST2:
		buz=0;
		if (klawiatura)
		{
			if (klawisz==L3)
			{
				stan=ST3;
				CZUWANIE
				startuj_xtime_out(20);
			}
			else
			{
				stan=start;
				STOP_TIME_OUT
				CZUWANIE
			}
		}
		if (time_out)
		{
			time_out=0;			
			STOP_TIME_OUT
			stan=start;
			CZUWANIE
		}
		break;
	case ST3:
		buz=0;
		if (klawiatura)
		{
			if (klawisz==L4)
			{
				stan=ST4;
				buz=1;
				DISARMED
				startuj_xtime_out(900);
			}
			else
			{
				stan=start;
				STOP_TIME_OUT
				CZUWANIE
			}
		}
		if (time_out)
		{
			time_out=0;
			STOP_TIME_OUT
			stan=start;
			CZUWANIE
		}
		break;
	case ST4:	/* dlugi time_out juz biega */
		if (klawiatura)
		{
			if (klawisz==L5)
			{
				buz=1;
				stan=ST5;
				DISARMED
			}
			else
			{
				if (klawisz==CHECK_BTN2)
					blink_diode(3);
				else
				{
					stan=ST4;
					buz=1;
					DISARMED
				}
			}
		}
		if (time_out)
		{
			time_out=0;
			stan=zlodziej;
			buz=0;
			ALARM
		}
		break;
	case ST5:
		if (klawiatura)
		{
			if (klawisz==L6)
			{
				stan=ST6;
				buz=0;
				STOP_TIME_OUT
				DISARMED
				BUZZER_OFF
			}
			else
			{
				stan=ST4;
				buz=1;
			}
		}
		if (time_out)
		{
			time_out=0;
			stan=zlodziej;
			buz=0;
			ALARM
		}
		break;
	case ST6:
		if (klawiatura)
		{
			if (klawisz==L1)
			{
				stan=ST7;
				DISARMED
				startuj_xtime_out(20);
			}
			else
			{
				if (klawisz==CHECK_BTN)
					blink_diode(3);
				else
				{
					if (klawisz==L5)
					{
						stan=ST8;
						DISARMED
						startuj_xtime_out(20);
					}
					else
						stan=ST6;
				}
			}
		}
		if (time_out)
		{
			time_out=0;
			STOP_TIME_OUT
			stan=ST6;
			DISARMED
		}
		break;
	case ST7:
		if (klawiatura)
		{
			if (klawisz==L2)
			{
				stan=start;
				STOP_TIME_OUT
				CZUWANIE
			}
			else
			{
				stan=ST6;
				STOP_TIME_OUT
				DISARMED
			}
		}
		if (time_out)
		{
			time_out=0;
			STOP_TIME_OUT
			stan=ST6;
			DISARMED
		}
		break;
	case ST8:
		if (klawiatura)
		{
			if (klawisz==L6)
			{
				stan=ST4;
				DISARMED
				buz=1;
				startuj_xtime_out(900);
			}
			else
			{
				stan=ST6;
				STOP_TIME_OUT
				buz=0;
				DISARMED
			}
		}
		if (time_out)
		{
			time_out=0;
			STOP_TIME_OUT
			stan=ST6;
			DISARMED
		}
		break;
	case zlodziej:
		if (klawiatura)
			if (klawisz==Z1)
			{
				stan=zl1;
				ALARM
				startuj_xtime_out(10);
			}
		if (time_out)
		{
			time_out=0;
			ALARM
		}
		break;
	case zl1:
		if (klawiatura)
		{
			if (klawisz==Z2)
			{
				stan=zl2;
				ALARM
				startuj_xtime_out(10);
			}
			else
			{
				stan=zlodziej;
				ALARM
				STOP_TIME_OUT
			}
		}
		if (time_out)
		{
			time_out=0;
			stan=zlodziej;
			ALARM
			STOP_TIME_OUT
		}
		break;
	case zl2:
		if (klawiatura)
		{
			if (klawisz==Z3)
			{
				stan=zl3;
				ALARM
				startuj_xtime_out(10);
			}
			else
			{
				stan=zlodziej;
				ALARM
				STOP_TIME_OUT
			}
		}		
		if (time_out)
		{
			time_out=0;
			stan=zlodziej;
			ALARM
			STOP_TIME_OUT
		}
		break;
	case zl3:
		if (klawiatura)
		{
			if (klawisz==Z4)
			{
				stan=zl4;
				ALARM
				startuj_xtime_out(10);
			}
			else
			{
				stan=zlodziej;
				ALARM
				STOP_TIME_OUT
			}
		}
		if (time_out)
		{
			time_out=0;
			stan=zlodziej;
			ALARM;
			STOP_TIME_OUT
		}
		break;
	case zl4:
		if (klawiatura)
		{
			if (klawisz==Z5)
			{
				stan=start;
				CZUWANIE
				
				DIODA_OFF
				STOP_TIME_OUT
			}
			else
			{
				stan=zlodziej;
				ALARM
				STOP_TIME_OUT
			}
		}
		if (time_out)
		{
			time_out=0;
			stan=zlodziej;
			STOP_TIME_OUT
		}
		break;
	default:
		/*cos nie tak....*/
		stan=ST6;
		STOP_TIME_OUT
		DISARMED
		time_out=0;
	};
	///////////////////////////
	// bylo jakies zdarzenie -
	// jesli w jego wyniku przeszlismy do startu to wlaczamy timeout do power down'a
	// jesli do jakiegos innego stanu to wylaczamy ten time-out
	if (stan!=start)
	{
		STOP_POWER_DOWN_TIME_OUT
	}
	else
		startuj_time_out_power_down();
}


main()
{

	inicjalizacja();
	blink_diode(2);
	while (1)
	{	
		process_zdarzenie();
		CNZ();
		/* a teraz czekac na jakies zdarzenie */
	}
	return 0;
}


void przerwanieT0 () __interrupt(2) __using(1)
{
	/*najwyzszy priorytet - zglaszane co 50ms*/
	/* timer programowy nr 0*/
	if (time_out_enabled)
	{
		/* obsluga timerow programowych */
		time_out_repetitions--;
		if (buz)
		{
			if (buzzer_time_out_enabled==0)
				if (time_out_repetitions<140)
				{
					blink_buzzer(7);
				}
				else
					BUZZER_OFF
		}
		if (time_out_repetitions==0)
		{
			time_out=1;
			time_out_enabled=0;
		}
	}
	else
		time_out=0;
	/* timer programowy nr 1 */
	if (time_out1_enabled)
	{
		/* obsluga timerow programowych */
		time_out1_repetitions--;
		if (time_out1_repetitions==0)
		{
			time_out1=1;
			time_out1_enabled=0;
		}
	}
	else
		time_out1=0;
   /* time out buzzera */
	if (buzzer_time_out_enabled)
	{
		/* obsluga timerow programowych */
		buzzer_time_out_repetitions--;
		if (buzzer_time_out_repetitions==0)
		{
			buzzer_time_out=1;
			buzzer_time_out_enabled=0;
		}
	}
	else
		buzzer_time_out=0;
	/********************************************
	 * poczatek przegladu klawiatury
	 ********************************************/
	
	P1=0x2B;
	if (keyboardSnapShot==INVALID_KEYBOARD_SNAP_SHOT)
	{
		/* tutaj sprawdzenie czy sie nie zwolnila bo ostatnio byla jeszcze wcisnieta */
		if (P1!=0x2B)
			keyboardSnapShot=INVALID_KEYBOARD_SNAP_SHOT; /*dalej wcisnieta*/
		else
		{
			keyboardSnapShot=0x2B;	/* juz zwolniona */
		}
	}
	else
	{
		/* ostatnio nie byla wcisnieta badz byla wcisnieta */
		if (keyboardSnapShot==0x2B)
		{
			/* ostatnio byla zwolniona */
			keyboardSnapShot=P1; /*i juz - jesli cos bylo wcisniete to bedzie w nastepnym podejsciu - a jesli nie
									to bedzie to 0x2B */
		}
		else
		{
			/* cos bylo wcisniete ostatnio */
			if (keyboardSnapShot!=P1)
				keyboardSnapShot=P1;	/* moze nastepnym razem bedzie OK */
			else
			{
				/* ostatnio bylo wcisniete to samo co i tym razem - nie trzeba update'owac keyboardSnapShot'a*/
				switch(P1)
				{
				case 0x0B:
					wiersz=1;		
					break;
				case 0x23:
					wiersz=2;
					break;
				case 0x2A:
					wiersz=3;
					break;
				case 0x29:
					wiersz=4;
					break;
				default:
					wiersz=0;
				}

				if (wiersz>0 && wiersz<5)
				{
					/*scanowanie kolumn*/
					P1=0xD4;
					
					switch(P1)
					{
					case 0x94:
						kolumna=1;
						break;
					case 0xC4:
						kolumna=2;
						break;
					case 0xD0:
						kolumna=3;
						break;
					default:
						kolumna=0;	
					}
					if (kolumna>0 && kolumna<4)
					{
						P1=0x2B;
						klawiatura=1;
						keyboardSnapShot=INVALID_KEYBOARD_SNAP_SHOT;	/*bo bedziemy czekac na zwolnienie*/
						if (wiersz<4)
							klawisz=kolumna+3*(wiersz-1);
						else
							switch (kolumna)
							{
							case 2:
								klawisz=0;
								break;
							case 1:
								klawisz=10;
								break;
							case 3:
								klawisz=11;
								break;
							default:
								/* nie powinno byc...*/
								klawiatura=0;
								
								break;
							}		
					}
					else
					{
						/*wcisnieto niepoprawnie kolumne*/
						P1=0x2B;
						keyboardSnapShot=P1;
					}
				}
				else
				{
					/*wcisnieto niepoprawnie we wierszach*/
					P1=0x2B;
					keyboardSnapShot=P1;
				}
			}
		}
	}
	P1=0x2B;
	
	/********************************************
	 * koniec przegladu klawiatury
	 ********************************************/

	/* start timera 0 na nastepne 50 ms */
	TH0=0x0F;	/*na 50 ms bo mozna maksymalnie na 53 z kawalkiem...*/
	TL0=0xEE;

	ET0=1;
	TR0=1;
}

void przerwanieT1 () __interrupt(4) __using(2)
{
	TR1=0;
	ET1=0;
	power_down--;
	if (power_down==0 && stan==start)
		POWER_DOWN_MODE
	TH1=0;
	TL1=0;
	ET1=1;
	TR1=1;
}
